package com.nongcai159.mall.lib_common.http

import android.content.Context
import android.net.ConnectivityManager
import com.nongcai159.mall.lib_common.BuildConfig
import com.nongcai159.mall.lib_common.base.BaseApplication
import com.nongcai159.mall.lib_common.utils.FileUtils
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit

/**
 * okhttp
 *
 *
 * Created by tanbiheng on 2017/9/19.
 */

class OkHttpManager private constructor() {
    private var okHttpClient: OkHttpClient? = null

    private val MAX_CACHE_SIZE = (1024 * 1024 * 10).toLong()// 最大缓存10Mb
    private val CACHE_DIR = FileUtils.CACHE_DIR// 缓存文件目录
    private val CACHE_FILE_NAME = "cache"// 缓存文件名

    fun getOkHttpClient(): OkHttpClient {
        if (okHttpClient == null) {
            //开启Log
            val logInterceptor = HttpLoggingInterceptor()
            if (BuildConfig.DEBUG) {
                logInterceptor.level = HttpLoggingInterceptor.Level.BODY
            } else {
                logInterceptor.level = HttpLoggingInterceptor.Level.NONE
            }
            //缓存
            val cacheFile = File(CACHE_DIR, CACHE_FILE_NAME)
            val cache = Cache(cacheFile, MAX_CACHE_SIZE)

            //增加头部信息
            val headerInterceptor = Interceptor { chain ->
                val build = chain.request().newBuilder()
                        .addHeader("Content-Type", "text/xml")
                        .build()
                chain.proceed(build)
            }

            val noNetInterceptor = Interceptor { chain ->
                var request = chain.request()
                if (!isNetWorkAvailable) {
                    request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build()
                    val proceed = chain.proceed(request)
                    return@Interceptor proceed.newBuilder()
                            .removeHeader("Pragma")
                            .removeHeader("Cache-Control")
                            .header("Cache-Control", CACHE_CONTROL_CACHE)
                            .build()
                }
                chain.proceed(request)
            }

            val cacheInterceptor = object : Interceptor {

                private var response: Response? = null
                private var cacheControl: CacheControl? = null

                @Throws(IOException::class)
                override fun intercept(chain: Interceptor.Chain): Response? {
                    val request = chain.request()
                    cacheControl = request.cacheControl()

                    val proceed = chain.proceed(request)
                    if (isNetWorkAvailable) {
                        if (cacheControl!!.maxAgeSeconds() < 0) {
                            response = proceed.newBuilder()
                                    .removeHeader("Pragma")
                                    .removeHeader("Cache-Control")
                                    .header("Cache-Control", CACHE_CONTROL_AGE).build()
                        } else {
                            response = proceed.newBuilder()
                                    .removeHeader("Pragma")
                                    .removeHeader("Cache-Control")
                                    .header("Cache-Control", cacheControl!!.toString()).build()
                        }
                        return response
                    }
                    return chain.proceed(request)
                }
            }

            //添加get/post公共请求参数
            val basicParamsInterceptor = BasicParamsInterceptor.Builder()
                    //                    .addQueryParam(Constant.CFROM, ApiConfig.CFROM)// 平台
                    //                    .addQueryParam(Constant.VERSION, AppConfig.getVersionChars())// 版本号
                    //                    .addQueryParam(Constant.CHANNEL, AppConfig.getAppChannel())// 渠道号
                    .build()

            okHttpClient = OkHttpClient.Builder()
                    .readTimeout(READ_TIME_OUT.toLong(), TimeUnit.MILLISECONDS)
                    .connectTimeout(CONNECT_TIME_OUT.toLong(), TimeUnit.MILLISECONDS)
                    .addInterceptor(basicParamsInterceptor)
                    .addInterceptor(headerInterceptor)
                    .addInterceptor(logInterceptor)
                    .addInterceptor(noNetInterceptor)
                    .addNetworkInterceptor(cacheInterceptor)
                    .retryOnConnectionFailure(true)
                    .cache(cache)
                    .build()
        }


        return okHttpClient!!
    }

    companion object {
        //读超时长，单位：毫秒
        private val READ_TIME_OUT = 10000
        //连接时长，单位：毫秒
        private val CONNECT_TIME_OUT = 10000

        /*************************缓存设置 */
        /*
        1. noCache 不使用缓存，全部走网络

        2. noStore 不使用缓存，也不存储缓存

        3. onlyIfCached 只使用缓存

        4. maxAge 设置最大失效时间，失效则不使用 需要服务器配合

        5. maxStale 设置最大失效时间，失效则不使用 需要服务器配合 感觉这两个类似 还没怎么弄清楚，清楚的同学欢迎留言

        6. minFresh 设置有效时间，依旧如上

        7. FORCE_NETWORK 只走网络

        8. FORCE_CACHE 只走缓存
        */

        /**
         * 设缓存有效期为两天
         */
        private val CACHE_STALE_SEC = (60 * 24 * 2).toLong()
        /**
         * 查询缓存的Cache-Control设置，为if-only-cache时只查询缓存而不会请求服务器，max-stale可以配合设置缓存失效时间
         * max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值，那么客户机可接收超出超时期指定值之内的响应消息。
         */
        private val CACHE_CONTROL_CACHE = "public, only-if-cached, max-stale=$CACHE_STALE_SEC"
        /**
         * 查询网络的Cache-Control设置，头部Cache-Control设为max-age=0
         * (假如请求了服务器并在a时刻返回响应结果，则在max-age规定的秒数内，浏览器将不会发送对应的请求到服务器，数据由缓存直接返回)时则不会使用缓存而请求服务器
         */
        private val CACHE_CONTROL_AGE = "max-age=0"

        @Volatile
        private var INSTANCE: OkHttpManager? = null

        val instance: OkHttpManager?
            get() {

                if (INSTANCE == null) {
                    synchronized(OkHttpManager::class.java) {
                        if (INSTANCE == null) {
                            INSTANCE = OkHttpManager()
                        }
                    }
                }
                return INSTANCE
            }

        // 检查网络是否可用
        // 当前网络不可用
        val isNetWorkAvailable: Boolean
            get() {
                val manager = BaseApplication.INSTANCE!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                val networkinfo = manager.activeNetworkInfo
                return !(networkinfo == null || !networkinfo.isAvailable)
            }
    }
}
